﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using PloobsEngine.SceneControl;
using PloobsEngine.MessageSystem;

namespace PloobsEngine.Cameras
{
    public class CameraFollowPath : ICamera
    {
        private CameraPathData data;
        private String nextCam;
        private IWorld world;
        private bool ended = false;
        private bool onLoop = false;

        public bool OnLoop
        {
            get { return onLoop; }
            set { onLoop = value; }
        }

        public bool Ended
        {
            get { return ended; }
            set { ended = value; }
        }
        
        public void Restart()     
        {
            ended = false;
            time = 0;
        }

        public CameraFollowPath(CameraPathData data,IWorld world , String nextCam )
        {            
            this.world = world;
            this.nextCam = nextCam;
            this.data = data;            
            _projection = Matrix.CreatePerspectiveFieldOfView(_fieldOdView, _aspectRatio, _nearPlane, _farPlane);
        }
        

        private void init(Vector3 position, Vector3 Target)
        {
            this._target = Target;
            this._position = position;
            _view = Matrix.CreateLookAt(_position, _target, _up);            
        }

        #region Fields

        private Vector3 _position = Vector3.Right;
        private Vector3 _target = Vector3.Zero;
        private bool _hasmoved = true;
        private Vector3 _up = Vector3.Up;
        private Quaternion _rotation = Quaternion.Identity;
        private float _fieldOdView = MathHelper.PiOver4;
        private float _aspectRatio = 4f / 3f;
        private float _nearPlane = 1.0f;
        private float _farPlane = 1000.0f;
        private Matrix _view;
        private Matrix _projection;
        private BoundingBox _box;
        private BoundingFrustum _frustrum;
        private int _id;

        #endregion

        #region ICamera Members

        public bool Hasmoved
        {
            get { return _hasmoved; }
        }

        public Microsoft.Xna.Framework.Vector3 Position
        {
            get
            {
                return _position;
            }
            set
            {
                this._position = value;                 

            }
        }

        public Microsoft.Xna.Framework.Vector3 Target
        {
            get
            {
                return this._target;                    
            }
            set
            {
                this._target = value;                
            }
        }

        public Microsoft.Xna.Framework.Vector3 Up
        {
            get
            {
                return _up;
            }
            set
            {
                this._up = value;                
            }
        }

        public Microsoft.Xna.Framework.Quaternion Rotation
        {
            get
            {
                throw new Exception("not yet implemented");
             //   _view = Matrix.CreateLookAt(_position, _target, _up);
              //  _rotation = Quaternion.CreateFromRotationMatrix(Matrix.Invert(_view));
               // return _rotation; 
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public float FieldOfView
        {
            get
            {
                return this._fieldOdView;
            }
            set
            {
                this._fieldOdView = value;
                _projection = Matrix.CreatePerspectiveFieldOfView(_fieldOdView,_aspectRatio, _nearPlane, _farPlane);

            }
        }

        public float AspectRatio
        {
            get
            {
                return _aspectRatio;
            }
            set
            {
                this._aspectRatio = value;
                _projection = Matrix.CreatePerspectiveFieldOfView(_fieldOdView, _aspectRatio, _nearPlane, _farPlane);
            }
        }

        public float NearPlane
        {
            get
            {
                return this._nearPlane;
            }
            set
            {
                this._nearPlane = value;
                _projection = Matrix.CreatePerspectiveFieldOfView(_fieldOdView, _aspectRatio, _nearPlane, _farPlane);
            }
        }

        public float FarPlane
        {
            get
            {
                return this._farPlane;
            }
            set
            {
                this._farPlane = value;
                _projection = Matrix.CreatePerspectiveFieldOfView(_fieldOdView, _aspectRatio, _nearPlane, _farPlane);
            }
        }

        public Microsoft.Xna.Framework.Matrix View
        {
            get { return _view; }
        }

        public Microsoft.Xna.Framework.Matrix Projection
        {
            get { return _projection; }
        }

        public Microsoft.Xna.Framework.BoundingFrustum BoundingFrustum
        {
            get 
            {
                
                if (_hasmoved)
                {
                this._frustrum = new BoundingFrustum(_view * _projection);
                return this._frustrum;
                }
                return this._frustrum;

            }
        }

        public Microsoft.Xna.Framework.BoundingBox BoundingBox
        {
            get
            {
                this._box = BoundingBox.CreateFromPoints(BoundingFrustum.GetCorners());
                return this._box;
                
            }
        }

        private float time;
        public void Update(Microsoft.Xna.Framework.GameTime gt)
        {
            time += (float)  gt.ElapsedGameTime.TotalMilliseconds;
            if (data.getMaxTime() < time)
            {
                if (onLoop == true)
                {
                    Restart();
                    return;
                }

                ICamera cnext = world.CameraManager.GetCamera(nextCam);

                cnext.Position = this.Position;
                cnext.Target = this.Target;
                cnext.Up = this.Up;

                world.CameraManager.RemoveCamera(world.CameraManager.GetActiveCameraName());
                world.CameraManager.SetActiveCamera(cnext.Name);
                ended = true;
                return;
            }
            _target = data.GetTarget(time);
            _up = data.GetUp(time);
            _position = data.GetHead(time);
            _view = Matrix.CreateLookAt(_position, _target, _up);            
        }

        #endregion

        #region IEntity Members

        public int getId()
        {
            return _id;
        }

        public void setId(int id)
        {
            this._id = id;
        }

        #endregion

        #region IRecieveMessageEntity Members

        public virtual bool HandleThisMessageType(SenderType type)
        {
            return true;
        }

        public virtual void HandleMessage(Message mes)
        {
            
        }

        #endregion

        #region ICamera Members

        public void Serialize(System.Xml.XmlTextWriter textWriter)
        {
                //SerializerHelper.SerializeVector3(Position,"Position",textWriter);                
                //SerializerHelper.SerializeVector3(Target,"Target",textWriter);
        }



        public void DeSerialize(System.Xml.XmlNode node, EngineStuff engine, IWorld world)
        {
            //Vector3 pos =  SerializerHelper.DeserializeVector3("Position",node);
            //Vector3 tar =  SerializerHelper.DeserializeVector3("Target",node);
            //init(pos, tar);
        }

        #endregion

        #region ICamera Members

        String name;
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                this.name = value;
            }
        }

        #endregion
    }
}
